﻿using System;
using System.ComponentModel;
using System.Linq;
using System.Collections.Generic;
using Microsoft.VisualStudio.SharePoint;

namespace CodeCounsel.SharePoint.DevTools.ItemTypes
{
    [TypeConverter]
    public class SPMetalProperties
    {
        class SPMetalPropertiesDescriptionProvider
            : TypeConverter
        {
            public override PropertyDescriptorCollection GetProperties(
                ITypeDescriptorContext context, object value, Attribute[] attributes)
            {
                SPMetalProperties configProperties = (SPMetalProperties)value;
                PropertyDescriptorCollection properties = base.GetProperties(context, value, attributes);
                if (configProperties.Mode == SPMetalSource.CurrentDeploymentSite)
                {
                    PropertyDescriptor urlDescriptor = properties["Url"];
                    properties.Remove(urlDescriptor);
                    properties.Add(new ReadOnlyPropertyDescriptor("Url", null)
                    {
                        InnerDescriptor = urlDescriptor,
                        ReadOnlyEvaluator = p => true
                    });
                }
                return properties;
            }
        }

        class ReadOnlyPropertyDescriptor
            : PropertyDescriptor
        {
            public PropertyDescriptor InnerDescriptor { get; set; }
            public Func<PropertyDescriptor, bool> ReadOnlyEvaluator { get; set; }

            public override bool CanResetValue(object component)
            {
                return InnerDescriptor.CanResetValue(component);
            }

            public ReadOnlyPropertyDescriptor(string name, Attribute[] attrs)
                : base(name, attrs)
            {
            }

            public override Type ComponentType
            {
                get { return InnerDescriptor.ComponentType; }
            }

            public override object GetValue(object component)
            {
                return InnerDescriptor.GetValue(component);
            }

            public override bool IsReadOnly
            {
                get 
                { 
                    return ReadOnlyEvaluator != null ? 
                        ReadOnlyEvaluator(InnerDescriptor) : 
                        InnerDescriptor.IsReadOnly; 
                }
            }

            public override Type PropertyType
            {
                get { return InnerDescriptor.PropertyType; }
            }

            public override void ResetValue(object component)
            {
                InnerDescriptor.ResetValue(component);
            }

            public override void SetValue(object component, object value)
            {
                InnerDescriptor.SetValue(component, value);
            }

            public override bool ShouldSerializeValue(object component)
            {
                return InnerDescriptor.ShouldSerializeValue(component);
            }
        }

        const string PropertyMode = "CodeCounsel.SharePoint.DevTools.SPMetalDefinition.Mode";
        const string PropertyUrl = "CodeCounsel.SharePoint.DevTools.SPMetalDefinition.Url";
        const string PropertySerialization = "CodeCounsel.SharePoint.DevTools.SPMetalDefinition.Serialization";
        IDictionary<string, string> _properties;
        ISharePointProjectItem _owner;
        SPMetalDefinition _definition;

        [DefaultValue(SPMetalSource.CurrentDeploymentSite)]
        [Category(PropertyCategory.DevTools)]
        [RefreshProperties(RefreshProperties.All)]
        public SPMetalSource Mode
        {
            get
            {
                string mode;
                _properties.TryGetValue(PropertyMode, out mode);
                return mode != null ? (SPMetalSource)Enum.Parse(typeof(SPMetalSource), mode) : SPMetalSource.CurrentDeploymentSite;
            }
            set 
            { 
                _properties[PropertyMode] = value.ToString();
                _definition.ForceRegenerate(_owner);
            }
        }

        [DefaultValue((string)null)]
        [Category(PropertyCategory.DevTools)]
        public string Url
        {
            get
            {
                if (Mode == SPMetalSource.CurrentDeploymentSite)
                {
                    return _owner.Project.SiteUrl.ToString();
                }
                else
                {
                    string url;
                    _properties.TryGetValue(PropertyUrl, out url);
                    return url;
                }
            }
            set
            {
                _properties[PropertyUrl] = value;
                _definition.ForceRegenerate(_owner);
            }
        }

        [DefaultValue(SPMetalSerialization.None)]
        [Category(PropertyCategory.DevTools)]
        public SPMetalSerialization Serialization
        {
            get
            {
                string mode;
                _properties.TryGetValue(PropertySerialization, out mode);
                return mode != null ? (SPMetalSerialization)Enum.Parse(typeof(SPMetalSerialization), mode) : SPMetalSerialization.None;
            }
            set 
            { 
                _properties[PropertySerialization] = value.ToString();
                _definition.ForceRegenerate(_owner);
            }
        }

        public SPMetalProperties(SPMetalDefinition definition, ISharePointProjectItem owner, IDictionary<string, string> properties)
        {
            _owner = owner;
            _properties = properties;
            _definition = definition;
        }
    }
}
